package dataImport.action;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import dataImport.action.abstracts.AbstractEntityReader;
import dataImport.action.helper.UnityGuardian;
import dataImport.action.manager.EntityReaderManager;
import dataImport.exception.DuplicateAttributeException;
import dataImport.exception.MissingAttributeException;
import dataImport.exception.NoEntityRelatedWithException;
import dataImport.exception.UniquenessRestrictionViolatedException;
import dataImport.model.CustomAction;
import dataImport.model.Object;
import dataImport.model.Place;
import dataImport.model.Requirement;
import dataImport.model.State;
import dataImport.model.StaticRequirement;
import dataImport.model.abstracts.AbstractEntity;


public class RequirementReader extends AbstractEntityReader {

	private static final long serialVersionUID = 445396337134916715L;

	private static final String ATTRIBUTE_VALUE = "value";

	private UnityGuardian commandActionIdStaticRequirementEntityId;

	public RequirementReader(final EntityReaderManager entityReaderManager) {
		super(entityReaderManager);
		this.commandActionIdStaticRequirementEntityId = new UnityGuardian();
	}

	@Override
	protected AbstractEntity createEntity(final Element element) {
		final String name = element.getNodeName();
		final String value = element.getAttribute(ATTRIBUTE_VALUE);
		final Element parentNode = (Element) element.getParentNode();
		final String parentNodeName = parentNode.getNodeName();
		final String parentNodeId = parentNode.getAttribute(AbstractEntityReader.ATTRIBUTE_ID);

		this.verifyRestrictions(parentNodeName, parentNodeId, name, value);

		final CustomAction customAction = (CustomAction) super.getEntityReaderManager().getCustomActionReader().getEntityWithId(parentNodeId);
		final StaticRequirement staticRequirement = StaticRequirement.get(name);

		switch (staticRequirement) {
			case REQUIREOBJECT:
				final Object object = (Object) super.getEntityReaderManager().getObjectReader().getEntityWithId(value);
				return new Requirement(customAction, staticRequirement, object);
			case REQUIRESTATE:
				final State state = (State) super.getEntityReaderManager().getStateReader().getEntityWithId(value);
				return new Requirement(customAction, staticRequirement, state);
			case REQUIREPLACE:
				final Place place = (Place) super.getEntityReaderManager().getPlaceReader().getEntityWithId(value);
				return new Requirement(customAction, staticRequirement, place);
			default:
				break;
		}

		return null;
	}

	@Override
	public void read(final Document document) {
		for (StaticRequirement staticRequirement : StaticRequirement.values()) {
			super.read(staticRequirement.getName(), document);
		}
	}

	private void verifyRestrictions(final String commandActionName, final String commandActionId, final String staticRequirementName, final String entityId) {
		if (entityId.isEmpty()) {
			throw new MissingAttributeException(ATTRIBUTE_VALUE);
		}

		try {
			this.commandActionIdStaticRequirementEntityId.ensureUniqueness(commandActionId, staticRequirementName, entityId);
		}
		catch (final UniquenessRestrictionViolatedException e) {
			throw new DuplicateAttributeException("requirement", staticRequirementName);
		}

		if (!commandActionName.equals(CustomActionReader.ENTITY_NAME)) {
			throw new NoEntityRelatedWithException(staticRequirementName, CustomActionReader.ENTITY_NAME);
		}
	}
}
